#include "EyerWASMHttpFetch_FetchEvent.hpp"

#include <emscripten.h>

extern "C"
{
EMSCRIPTEN_KEEPALIVE int EyerWASMHttpFetch_FetchEvent_Fetch(void * ctx, const char * url, const char * rangeStart, const char * rangeEnd);

EMSCRIPTEN_KEEPALIVE int EyerWASMHttpFetch_FetchEvent_Fetch_On_Header_Recv(void * ctx, int httpStatus, const char * contentLengthStr, const char * rangeLengthStr)
{
    Eyer::EyerWASMHttpFetch_FetchEvent * xmlHttpRequest = (Eyer::EyerWASMHttpFetch_FetchEvent *)ctx;
    int64_t contentLength = atoll(contentLengthStr);
    int64_t rangeLength = atoll(rangeLengthStr);
    return xmlHttpRequest->EyerWASMHttpFetch_FetchEvent_Fetch_On_Header_Recv(httpStatus, contentLength, rangeLength);
}

EMSCRIPTEN_KEEPALIVE int EyerWASMHttpFetch_FetchEvent_Fetch_On_Body_Recv(void * ctx, uint8_t * buf, int bufSize)
{
    Eyer::EyerWASMHttpFetch_FetchEvent * xmlHttpRequest = (Eyer::EyerWASMHttpFetch_FetchEvent *)ctx;
    return xmlHttpRequest->EyerWASMHttpFetch_FetchEvent_Fetch_On_Body_Recv(buf, bufSize);
}

EMSCRIPTEN_KEEPALIVE int EyerWASMHttpFetch_FetchEvent_Fetch_On_Fail(void * ctx)
{
    Eyer::EyerWASMHttpFetch_FetchEvent * xmlHttpRequest = (Eyer::EyerWASMHttpFetch_FetchEvent *)ctx;
    return xmlHttpRequest->EyerWASMHttpFetch_FetchEvent_Fetch_On_Fail();
}
}

namespace Eyer
{
    EyerWASMHttpFetch_FetchEvent::EyerWASMHttpFetch_FetchEvent(const std::string & _url, int64_t _rangeStart, int64_t _rangeEnd)
        : url(_url)
        , rangeStart(_rangeStart)
        , rangeEnd(_rangeEnd)
    {

    }

    EyerWASMHttpFetch_FetchEvent::~EyerWASMHttpFetch_FetchEvent()
    {
        if(buf != nullptr) {
            free(buf);
            buf = nullptr;
        }
    }

    int EyerWASMHttpFetch_FetchEvent::Run()
    {
        std::unique_lock<std::mutex> lck(mtx);

        std::string rangeStartStr = std::to_string(rangeStart);
        std::string rangeEndStr = std::to_string(rangeEnd);

        fetchAbortKey = EyerWASMHttpFetch_FetchEvent_Fetch(this, url.c_str(), rangeStartStr.c_str(), rangeEndStr.c_str());
        return 0;
    }

    bool EyerWASMHttpFetch_FetchEvent::isHttpHeaderRecved()
    {
        return isHeaderRecved;
    }

    int EyerWASMHttpFetch_FetchEvent::EyerWASMHttpFetch_FetchEvent_Fetch_On_Header_Recv(int _httpStatus, int64_t _contentLength, int64_t _rangeLength)
    {
        std::unique_lock<std::mutex> lck(mtx);
        isHeaderRecved = true;
        httpStatus = _httpStatus;
        contentLength = _contentLength;
        rangeLength = _rangeLength;
        cond.notify_all();
        return 0;
    }

    int EyerWASMHttpFetch_FetchEvent::EyerWASMHttpFetch_FetchEvent_Fetch_On_Body_Recv(uint8_t * _buf, int _bufSize)
    {
        std::unique_lock<std::mutex> lck(mtx);

        if(buf != nullptr) {
            free(buf);
            buf = nullptr;
        }

        bufSize = _bufSize;
        buf = (uint8_t *)malloc(bufSize);
        memcpy(buf, _buf, bufSize);

        isHeaderRecved = true;
        isFinished = true;
        cond.notify_all();
        return 0;
    }

    int EyerWASMHttpFetch_FetchEvent::EyerWASMHttpFetch_FetchEvent_Fetch_On_Fail()
    {
        std::unique_lock<std::mutex> lck(mtx);
        httpStatus = 0;
        isHeaderRecved = true;
        isFinished = true;
        cond.notify_all();
        return 0;
    }

    int EyerWASMHttpFetch_FetchEvent::GetHttpStatus()
    {
        return httpStatus;
    }

    int EyerWASMHttpFetch_FetchEvent::GetBufferSize()
    {
        return bufSize;
    }

    uint8_t * EyerWASMHttpFetch_FetchEvent::GetBufferPtr()
    {
        return buf;
    }

    int64_t EyerWASMHttpFetch_FetchEvent::GetContentLength()
    {
        return contentLength;
    }

    int64_t EyerWASMHttpFetch_FetchEvent::GetRangeLength()
    {
        return rangeLength;
    }

    int EyerWASMHttpFetch_FetchEvent::GetFetchAbortKey()
    {
        return fetchAbortKey;
    }
}
